package com.smsc.headend.task.engine.service.task.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.primitives.Bytes;
import com.smsc.headend.common.constant.Constant;
import com.smsc.headend.common.constant.DeviceMfg;
import com.smsc.headend.common.constant.DeviceModel;
import com.smsc.headend.common.enums.errorcode.TaskExecuteErrorCode;
import com.smsc.headend.common.utils.RedisUtils;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.dmo.DLMSConfigDMO;
import com.smsc.headend.module.asset.dmo.MeterConfigDMO;
import com.smsc.headend.module.asset.dto.*;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.asset.entity.DeviceTypeGroup;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.asset.entity.SecurityHls;
import com.smsc.headend.module.asset.enums.SecurityLevel;
import com.smsc.headend.module.data.dmo.DeviceSAPandKeys;
import com.smsc.headend.module.data.dto.AnsiSubDataItemDTO;
import com.smsc.headend.module.data.dto.DLMSSubDataItemDTO;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.fwu.entity.TemplateFwUpgrade;
import com.smsc.headend.module.protocol.ansi.objects.Acse;
import com.smsc.headend.module.protocol.cosem.enums.DlmsDataType;
import com.smsc.headend.module.protocol.cosem.util.ByteNumberUtils;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.template.clock.entity.TemplateClockEntity;
import com.smsc.headend.module.template.dcu.entity.*;
import com.smsc.headend.module.template.tou.entity.TemplateTouDayEntity;
import com.smsc.headend.module.template.tou.entity.TemplateTouDayIntervalEntity;
import com.smsc.headend.module.template.tou.entity.TemplateTouSeasonEntity;
import com.smsc.headend.module.template.tou.entity.TemplateTouWeekEntity;
import com.smsc.headend.task.engine.exception.UDISTaskExecutorException;
import com.smsc.headend.task.engine.po.PacketParseResult;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.kms.KmsService;
import com.smsc.headend.task.engine.service.task.TaskPacketService;
import com.smsc.headend.task.engine.utils.AesUtils;
import com.smsc.headend.task.engine.utils.AnsiUtil;
import com.smsc.headend.task.engine.utils.GXByteBufferUtils;
import gurux.dlms.*;
import gurux.dlms.enums.*;
import gurux.dlms.internal.GXCommon;
import gurux.dlms.manufacturersettings.GXDLMSAttributeSettings;
import gurux.dlms.objects.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TaskPacketServiceImpl implements TaskPacketService {
    public static final String COMPOSE_BYTE_ERROR = "compose byte error {}";
    public static final String ENCODE_PACKET_FAIL = "encode packet fail";
    public static final String BUILD_PACKET_FAIL = "build packet fail";
    @Autowired
    RedisUtils redisUtils;

    @Autowired
    FeignAssetManagementService assetManagementRemoteService;

    @Autowired
    KmsService kmsService;

    @Value("${dlms.tou.season.format.one:3206,3207,3208}")
    public String[] sanxingTouFormatModelId;

    @Value("${dlms.timesync.clock-status.ok:3206,3207,3208}")
    public String[] clockStatusOkModelId;

    @Autowired
    AssetService assetService;

    @Override
    public byte[] buildReadWithListPacket(List<DataItemDTO> dataItemCosemList, Meter meter, MeterConfigDMO meterConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!meterConfigDMO.getIsShortName());
//        Object name = meter.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(meterConfigDMO.getInterfaceType()));

        // Read http://www.gurux.org/dlmsAddress
        // to find out how Client and Server addresses are counted.
        // Some manufacturers might use own Server and Client addresses.
        client.setClientAddress(1);
        client.setServerAddress(1);
        final int[] index = {0};

        Map<GXDLMSObject, Integer> map = new HashMap<>();
        dataItemCosemList.stream().forEach(dataItemDto -> {
            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
            GXDLMSObject object = new GXDLMSObject();
            if (meterConfigDMO.getIsShortName()) {
                object.setShortName(Integer.parseInt(dlmsSubDataItemDTO.getObis(), 16));
            } else {
                object.setLogicalName(dlmsSubDataItemDTO.getObis());
            }
            object.setObjectType(ObjectType.forValue(dlmsSubDataItemDTO.getClassId()));
            GXDLMSAttributeSettings item = new GXDLMSAttributeSettings();
            if (dlmsSubDataItemDTO.getAttributeId() != null) {
                item.setIndex(dlmsSubDataItemDTO.getAttributeId());
            }
            object.getAttributes().add(item);
            map.put(object, index[0]++);
        });

        client.getNegotiatedConformance().addAll(GXDLMSClient.getInitialConformance(!meterConfigDMO.getIsShortName()));
        try {
            byte[][] b = client.readList(Lists.newArrayList(map.entrySet()));
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemCosemList, e);
        }
        return null;

    }

    @Override
    public byte[] buildReadOneAttributePacket(DataItemDTO dataItemDto, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys) throws UDISTaskExecutorException {
        if (dataItemDto instanceof AnsiSubDataItemDTO) {
            AnsiSubDataItemDTO ansiSubDataItemDTO = (AnsiSubDataItemDTO) dataItemDto;
            byte[] data;
            // 读全表
            if (ansiSubDataItemDTO.getTableOffset() == 0 && ansiSubDataItemDTO.getByteCount() == 0) {
                data = AnsiUtil.formatPacketReadFullTable(ansiSubDataItemDTO.getTableId());
            } else {
                data = AnsiUtil.formatPacketReadPartTableByOffset(ansiSubDataItemDTO.getTableId(), ansiSubDataItemDTO.getTableOffset(), ansiSubDataItemDTO.getByteCount());
            }
            Acse acse = new Acse(deviceKeys.getLlsKey(), data, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));
            return acse.getPacket();
        } else {
//        DataItemDTO dataItemDto = dataItemCosemList.get(0);
            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
            GXDLMSClient client = new GXDLMSClient();
            //is shortName or not
            client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
            Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dlmsSubDataItemDTO.getObis(), 16) : dlmsSubDataItemDTO.getObis();

            // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
            client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));

            // Read http://www.gurux.org/dlmsAddress
            // to find out how Client and Server addresses are counted.
            // Some manufacturers might use own Server and Client addresses.
            client.setClientAddress(deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue());
            client.setServerAddress(1);

            boolean isCustomClassId = false;
            if (null == ObjectType.forValue(dlmsSubDataItemDTO.getClassId())) {
                isCustomClassId = true;
            }
            if (isCustomClassId) {
                // 自定义不支持的classId 先用1类组报文后 再替换掉classId
                try {
                    byte[][] b = client.read(name, ObjectType.forValue(1), dlmsSubDataItemDTO.getAttributeId());
                    // 替换 classId
                    b[0][11] = (byte) ((dlmsSubDataItemDTO.getClassId() >> 8) & 0xFF);
                    b[0][12] = (byte) (dlmsSubDataItemDTO.getClassId() & 0xFF);
                    return b[0];
                } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
                    log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
                    return null;
                }
            } else {
                try {
                    byte[][] b = client.read(name, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
                    return b[0];
                } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
                    log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
                    return null;
                }
            }
        }
    }

    @Override
    public byte[] buildReadOneAttributePacketWithMfgSn(DataItemDTO dataItemDto, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys) {
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dlmsSubDataItemDTO.getObis(), 16) : dlmsSubDataItemDTO.getObis();
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue());
        client.setServerAddress(1);

        try {
            byte[][] b = client.read(name, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
            GXByteBuffer attributeDescriptor = new GXByteBuffer();
            // Add AccessSelector flag.
            attributeDescriptor.setUInt8(0x01);
            // Add AccessSelector value.
            attributeDescriptor.setUInt8(02);
            //meter no
            GXByteBufferUtils.setVisibleStringAsciiByte(attributeDescriptor, meter.getMfgSn());
            byte[] data = new byte[attributeDescriptor.size()];
            System.arraycopy(attributeDescriptor.getData(), 0, data, 0, attributeDescriptor.size());
            GXDLMSTranslator translator = new GXDLMSTranslator(TranslatorOutputType.SIMPLE_XML);
            byte[] pdu = translator.getPdu(b[0]);
            int wrapIndex = Bytes.indexOf(b[0], pdu);
            byte[] packet = Bytes.concat(Arrays.copyOfRange(b[0], 0, b[0].length - 1), data);
            Integer pduLength = packet.length - wrapIndex;
            byte[] pduLengthByte = ByteNumberUtils.shortToByte2(pduLength.shortValue());
            System.arraycopy(pduLengthByte, 0, packet, wrapIndex - 2, 2);
            return packet;
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
            return null;
        }
    }

    @Override
    public byte[] writeSimpleDataPacket(List<DataItemDTO> dataItemCosemList, Meter meter, Object value, DLMSConfigDMO dlmsConfigDMO) throws UDISTaskExecutorException {
        if (value == null) {
            return null;
        }

        DataItemDTO dataItemDTO = dataItemCosemList.get(0);
        if (dataItemDTO instanceof AnsiSubDataItemDTO) {
            AnsiSubDataItemDTO dataItemDto = (AnsiSubDataItemDTO) dataItemCosemList.get(0);
            DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemDto.getRoleId());
            byte[] data = AnsiUtil.formatPacketWritePartTableByOffset(dataItemDto.getTableId(), dataItemDto.getTableOffset(), (byte[]) value, dataItemDto.getByteCount());
            Acse acse = new Acse(deviceKeys.getLlsKey(), data, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));
            return acse.getPacket();
        } else {
            DLMSSubDataItemDTO dataItemDto = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
            GXDLMSClient client = new GXDLMSClient();
            //is shortName or not
            client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
            Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

            // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
            client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));

            // Read http://www.gurux.org/dlmsAddress
            // to find out how Client and Server addresses are counted.
            // Some manufacturers might use own Server and Client addresses.
            client.setClientAddress(1);
            client.setServerAddress(1);

            try {
                DlmsDataType dlmsDataType = DlmsDataType.forName(dataItemDto.getObjType());
                if (null == dlmsDataType) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.BUILD_PACKET_ERROR_ITEM_INVALID.toString() + dataItemDto.toString());
                }
                byte[][] b = client.write(name, value, DataType.forValue(dlmsDataType.getValue()), ObjectType.forValue(dataItemDto.getClassId()), dataItemDto.getAttributeId());
                return b[0];
            } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
                log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
            }
            return null;
        }
    }


    @Override
    public byte[][] writeProfileCaptureObjects(List<DataItemDTO> dataItemCosemList, Meter meter, List<DataItemDTO> captureObjectLists, DLMSConfigDMO dlmsConfigDMO) {
        DataItemDTO dataItemDto = dataItemCosemList.get(0);
        if (dataItemDto instanceof AnsiSubDataItemDTO) {
            AnsiSubDataItemDTO ansiSubDataItemDTO = (AnsiSubDataItemDTO) dataItemDto;
            byte[] data = AnsiUtil.formatLpDataSource(ansiSubDataItemDTO, 32, captureObjectLists);
            DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemDto.getRoleId());
            Acse acse = new Acse(deviceKeys.getLlsKey(), data, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));
            return new byte[][]{acse.getPacket()};
        } else {
            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
            GXDLMSClient client = new GXDLMSClient();
            //is shortName or not
            client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
//        Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

            // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
            client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));

            setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

            // Read http://www.gurux.org/dlmsAddress
            // to find out how Client and Server addresses are counted.
            // Some manufacturers might use own Server and Client addresses.
            client.setClientAddress(1);
            client.setServerAddress(1);
            GXDLMSProfileGeneric gxdlmsProfileGeneric = new GXDLMSProfileGeneric();
            gxdlmsProfileGeneric.setLogicalName(dlmsSubDataItemDTO.getObis());
//        int index = 0;
            for (DataItemDTO dataItemDTO : captureObjectLists) {
                DLMSSubDataItemDTO dlmsSubDataItem = (DLMSSubDataItemDTO) dataItemDTO;
                GXDLMSObject gxdlmsObject = new GXDLMSProfileGeneric();
                gxdlmsObject.setLogicalName(dlmsSubDataItem.getObis());
                gxdlmsObject.setObjectType(ObjectType.forValue(dlmsSubDataItem.getClassId()));
                gxdlmsProfileGeneric.addCaptureObject(gxdlmsObject, dlmsSubDataItem.getAttributeId(), 0);
            }

            try {
                return client.write(gxdlmsProfileGeneric, dlmsSubDataItemDTO.getAttributeId());
            } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
                log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
            }

            return null;
        }
    }

    private void setMaxPduSize(GXDLMSClient client, String interfaceType, Integer maxPduSize) {
        client.setMaxReceivePDUSize(maxPduSize);
        if (StrUtil.equals(InterfaceType.HDLC.toString(), interfaceType)) {
            // 46默认最大size为128 修改maxInfoTx才生效
            client.getHdlcSettings().setMaxInfoTX(maxPduSize);
        }
    }

    @Override
    public byte[] setActiveCalendarPacket(DataItemDTO dataItemDto, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys, TouDataDTO touDataDTO) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
//        Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);

        GXDLMSActivityCalendar gxdlmsActivityCalendar = new GXDLMSActivityCalendar();
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
        gxdlmsActivityCalendar.setLogicalName(dlmsSubDataItemDTO.getObis());
        switch (dlmsSubDataItemDTO.getAttributeId()) {
            case 6: // calendarName passive
                if (StrUtil.isEmpty(touDataDTO.getCalendarName())) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.TOU_CALENDAR_NAME_IS_EMPTY.toString());
                }
                gxdlmsActivityCalendar.setCalendarNamePassive(touDataDTO.getCalendarName());
                break;
            case 7: // season profile passive
                List<TemplateTouSeasonEntity> seasonProfileList = touDataDTO.getSeasonProfileList();
                if (CollUtil.isEmpty(seasonProfileList)) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.TOU_SEASON_PROFILE_IS_EMPTY.toString());
                }
                List<GXDLMSSeasonProfile> seasonProfiles = new ArrayList<>();
                for (TemplateTouSeasonEntity seasonEntity : seasonProfileList) {
                    GXDLMSSeasonProfile gxdlmsSeasonProfile = new GXDLMSSeasonProfile();
                    gxdlmsSeasonProfile.setName(seasonEntity.getSeasonName());
                    String[] seasonStartTimes = seasonEntity.getStartTime().split("/"); // 日期格式为 mm/dd

                    GXDateTime start = getTouSeasonProfileStartTime(seasonStartTimes, meter.getModelId());
                    gxdlmsSeasonProfile.setStart(start);
                    gxdlmsSeasonProfile.setWeekName(seasonEntity.getWeekName());
                    seasonProfiles.add(gxdlmsSeasonProfile);
                }
                gxdlmsActivityCalendar.setSeasonProfilePassive(ArrayUtil.toArray(seasonProfiles, GXDLMSSeasonProfile.class));
                break;
            case 8: // week profile passive
                List<TemplateTouWeekEntity> weekProfileList = touDataDTO.getWeekProfileList();
                if (CollUtil.isEmpty(weekProfileList)) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.TOU_WEEK_PROFILE_IS_EMPTY.toString());
                }
                List<GXDLMSWeekProfile> weekProfiles = new ArrayList<>();
                for (TemplateTouWeekEntity weekEntity : weekProfileList) {
                    GXDLMSWeekProfile gxdlmsWeekProfile = new GXDLMSWeekProfile();
                    gxdlmsWeekProfile.setName(weekEntity.getWeekName());
                    gxdlmsWeekProfile.setMonday(weekEntity.getMondayId().intValue());
                    gxdlmsWeekProfile.setTuesday(weekEntity.getTuesdayId().intValue());
                    gxdlmsWeekProfile.setWednesday(weekEntity.getWednesdayId().intValue());
                    gxdlmsWeekProfile.setThursday(weekEntity.getThursdayId().intValue());
                    gxdlmsWeekProfile.setFriday(weekEntity.getFridayId().intValue());
                    gxdlmsWeekProfile.setSaturday(weekEntity.getSaturdayId().intValue());
                    gxdlmsWeekProfile.setSunday(weekEntity.getSundayId().intValue());

                    weekProfiles.add(gxdlmsWeekProfile);
                }
                gxdlmsActivityCalendar.setWeekProfileTablePassive(ArrayUtil.toArray(weekProfiles, GXDLMSWeekProfile.class));
                break;
            case 9: // day profile passive
                List<TemplateTouDayEntity> dayProfileList = touDataDTO.getDayProfileList();
                if (CollUtil.isEmpty(dayProfileList)) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.TOU_DAY_PROFILE_IS_EMPTY.toString());
                }
                List<GXDLMSDayProfile> dayProfiles = new ArrayList<>();
                for (TemplateTouDayEntity entity : dayProfileList) {
                    GXDLMSDayProfile dayProfile = new GXDLMSDayProfile();
                    dayProfile.setDayId(entity.getDayIndex().intValue());
                    List<TemplateTouDayIntervalEntity> times = entity.getTimes();
                    List<GXDLMSDayProfileAction> profileActions = new ArrayList<>();
                    for (TemplateTouDayIntervalEntity intervalEntity : times) {
                        GXDLMSDayProfileAction dayProfileAction = new GXDLMSDayProfileAction();
                        dayProfileAction.setScriptSelector(Integer.parseInt(intervalEntity.getScriptSelector()));
                        dayProfileAction.setScriptLogicalName(intervalEntity.getScriptLogicalName());
                        // 存的time为hh:mm 格式
                        String[] time = StrUtil.splitToArray(intervalEntity.getStartTime(), ":");
                        dayProfileAction.setStartTime(new GXTime(Integer.parseInt(time[0]), Integer.parseInt(time[1]), 0, 0));
                        profileActions.add(dayProfileAction);
                    }
                    dayProfile.setDaySchedules(ArrayUtil.toArray(profileActions, GXDLMSDayProfileAction.class));
                    dayProfiles.add(dayProfile);
                }
                gxdlmsActivityCalendar.setDayProfileTablePassive(ArrayUtil.toArray(dayProfiles, GXDLMSDayProfile.class));
                break;
            case 10: // activate passive calendar time
                if (StrUtil.isEmpty(touDataDTO.getActivateCalendarTime())) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.TOU_ACTIVATE_CALENDAR_TIME_IS_EMPTY.toString());
                }
                GXDateTime time = new GXDateTime(DateUtil.parse(touDataDTO.getActivateCalendarTime()));
                time.getStatus().add(ClockStatus.SKIPPED);
                gxdlmsActivityCalendar.setTime(time);
                break;
        }

        try {
            byte[][] b = client.write(gxdlmsActivityCalendar, dlmsSubDataItemDTO.getAttributeId());
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
        }
        return null;
    }

    private GXDateTime getTouSeasonProfileStartTime(String[] seasonStartTimes, Long modelId) {
        GXDateTime start;
        //                    GXDateTime start = new GXDateTime(0xFFFF, Integer.parseInt(seasonStartTimes[0]), Integer.parseInt(seasonStartTimes[1]), 0, 0, 0, 0);

        if (Arrays.stream(sanxingTouFormatModelId).map(Convert::toLong).anyMatch(modelId::equals)) {
            //Sanxing 联调Season表要求格式为 FFFF0101FFFFFFFFFF8000FF
            start = new GXDateTime(0xFFFF, Integer.parseInt(seasonStartTimes[0]), Integer.parseInt(seasonStartTimes[1]), 0xFF, 0xFF, 0xFF, 0xFF);
            start.setDayOfWeek(0xFF);
            start.getStatus().add(ClockStatus.SKIPPED);
            start.getSkip().add(DateTimeSkips.DEVITATION);
            start.getSkip().add(DateTimeSkips.MILLISECOND);
        } else {
            start = new GXDateTime(0xFFFF, Integer.parseInt(seasonStartTimes[0]), Integer.parseInt(seasonStartTimes[1]), 0, 0, 0, 0);
            start.setDayOfWeek(0xFF);
            start.getStatus().add(ClockStatus.SKIPPED);
            start.getSkip().add(DateTimeSkips.DEVITATION);
            start.getSkip().add(DateTimeSkips.MILLISECOND);
        }
        return start;
    }

    @Override
    public byte[] setSpecialDaysPacket(DataItemDTO dataItemDto, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys, TouDataDTO touDataDTO) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
        GXDLMSSpecialDaysTable gxdlmsSpecialDaysTable = new GXDLMSSpecialDaysTable(dlmsSubDataItemDTO.getObis());
        AtomicInteger i = new AtomicInteger(1);
        List<GXDLMSSpecialDay> days = touDataDTO.getTouSpecialDayList().stream().map(item -> {
            GXDLMSSpecialDay specialDay = new GXDLMSSpecialDay();
            specialDay.setIndex(i.getAndIncrement());
            specialDay.setDayId(Convert.toInt(item.getTouDayId()));
            String[] dateStrs = item.getSpecialDayTime().split("-");
            GXDate gxDate = new GXDate(NumberUtil.isNumber(dateStrs[0]) ? Integer.parseInt(dateStrs[0]) : Integer.parseInt(dateStrs[0], 16),
                    NumberUtil.isNumber(dateStrs[1]) ? Integer.parseInt(dateStrs[1]) : Integer.parseInt(dateStrs[1], 16),
                    NumberUtil.isNumber(dateStrs[2]) ? Integer.parseInt(dateStrs[2]) : Integer.parseInt(dateStrs[2], 16));
            if (StrUtil.equalsIgnoreCase(dateStrs[3], "FF")) {
                gxDate.getSkip().add(DateTimeSkips.DAY_OF_WEEK);
            }
            specialDay.setDate(gxDate);
            return specialDay;
        }).collect(Collectors.toList());
        gxdlmsSpecialDaysTable.setEntries(ArrayUtil.toArray(days, GXDLMSSpecialDay.class));

        try {
            byte[][] b = client.write(gxdlmsSpecialDaysTable, dlmsSubDataItemDTO.getAttributeId());
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error("compose byte error {}", dataItemDto, e);
        }
        return null;
    }

    @Override
    public byte[] setFriendlyDaysPacket(DataItemDTO dataItemDto, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys, TouDataDTO touDataDTO) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
        GXDLMSSpecialDaysTable gxdlmsSpecialDaysTable = new GXDLMSSpecialDaysTable(dlmsSubDataItemDTO.getObis());
        AtomicInteger i = new AtomicInteger(1);
        List<GXDLMSSpecialDay> days = touDataDTO.getTouFriendlyDayList().stream().map(item -> {
            GXDLMSSpecialDay specialDay = new GXDLMSSpecialDay();
            specialDay.setIndex(i.getAndIncrement());
            specialDay.setDayId(Convert.toInt(item.getTouDayId()));
            String[] dateStrs = item.getFriendlyDayTime().split("-");
            GXDate gxDate = new GXDate(NumberUtil.isNumber(dateStrs[0]) ? Integer.parseInt(dateStrs[0]) : Integer.parseInt(dateStrs[0], 16),
                    NumberUtil.isNumber(dateStrs[1]) ? Integer.parseInt(dateStrs[1]) : Integer.parseInt(dateStrs[1], 16),
                    NumberUtil.isNumber(dateStrs[2]) ? Integer.parseInt(dateStrs[2]) : Integer.parseInt(dateStrs[2], 16));
            if (StrUtil.equalsIgnoreCase(dateStrs[3], "FF")) {
                gxDate.getSkip().add(DateTimeSkips.DAY_OF_WEEK);
            }
            specialDay.setDate(gxDate);
            return specialDay;
        }).collect(Collectors.toList());
        gxdlmsSpecialDaysTable.setEntries(ArrayUtil.toArray(days, GXDLMSSpecialDay.class));

        try {
            byte[][] b = client.write(gxdlmsSpecialDaysTable, dlmsSubDataItemDTO.getAttributeId());
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error("compose byte error {}", dataItemDto, e);
        }
        return null;
    }

    @Override
    public byte[] setLimiterPacket(DataItemDTO dataItemDto, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys, LoadLimitDataDto limitDataDto) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
//        Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);

        GXDLMSLimiter gxdlmsLimiter = new GXDLMSLimiter();
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
        gxdlmsLimiter.setLogicalName(dlmsSubDataItemDTO.getObis());
        switch (dlmsSubDataItemDTO.getAttributeId()) {
            case 2: // monitor value
                DataItemDTO monitorDataItemDto = assetManagementRemoteService.getSubDataItemDto(meter.getMeterId(), limitDataDto.getMonitorDataItemId());
                if (null == monitorDataItemDto) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATAITEM_NOT_EXISTS.toString());
                }
                DLMSSubDataItemDTO monitorDlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDto;
                GXDLMSObject monitorObject = new GXDLMSObject();
                monitorObject.setLogicalName(monitorDlmsSubDataItemDTO.getObis());
                monitorObject.setObjectType(ObjectType.forValue(monitorDlmsSubDataItemDTO.getClassId()));
                gxdlmsLimiter.setmonitoredAttributeIndex(monitorDlmsSubDataItemDTO.getAttributeId());
                gxdlmsLimiter.setMonitoredValue(monitorObject);
                break;
            case 4: // threshold normal;
                if (null == limitDataDto.getNormal()) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.THRESHOLD_NORMAL_IS_NULL.toString());
                }
                gxdlmsLimiter.setDataType(4, DataType.forValue(DlmsDataType.DoubleLongUnsigned.getValue()));
                gxdlmsLimiter.setThresholdNormal(limitDataDto.getNormal());
                break;
            case 5: // threshold emergency
                if (null == limitDataDto.getEmergency()) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.THRESHOLD_EMERGENCY_IS_NULL.toString());
                }
                gxdlmsLimiter.setDataType(5, DataType.forValue(DlmsDataType.DoubleLongUnsigned.getValue()));
                gxdlmsLimiter.setThresholdEmergency(limitDataDto.getEmergency());
                break;
            case 6: // min over threshold duration
                if (null == limitDataDto.getOverDuration()) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.OVER_THRESHOLD_DURATION_IS_NULL.toString());
                }
                gxdlmsLimiter.setMinOverThresholdDuration(limitDataDto.getOverDuration());
                break;
            case 7: // min under threshold duration
                if (null == limitDataDto.getUnderDuration()) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.UNDER_THRESHOLD_DURATION_IS_NULL.toString());
                }
                gxdlmsLimiter.setMinUnderThresholdDuration(limitDataDto.getUnderDuration());
                break;
            case 8: // emergency profile
                if (null == limitDataDto.getEmergencyStartTime()) {
                    throw new UDISTaskExecutorException(TaskExecuteErrorCode.EMERGENCY_START_TIME_IS_NULL.toString());
                }
                GXDLMSEmergencyProfile emergencyProfile = gxdlmsLimiter.getEmergencyProfile();
                emergencyProfile.setID(limitDataDto.getTemplateId().intValue());
                // 时间格式 2020-01-01 06:00:00 或者为 FFFF-01-01 06:00:00 之类
                String[] dateTimeStr = limitDataDto.getEmergencyStartTime().split(" ");
                String[] dateStrs = dateTimeStr[0].split("-");
                String[] timeStrs = dateTimeStr[1].split(":");

                emergencyProfile.setActivationTime(new GXDateTime(NumberUtil.isNumber(dateStrs[0]) ? Integer.parseInt(dateStrs[0]) : Integer.parseInt(dateStrs[0], 16),
                        NumberUtil.isNumber(dateStrs[1]) ? Integer.parseInt(dateStrs[1]) : Integer.parseInt(dateStrs[1], 16),
                        NumberUtil.isNumber(dateStrs[2]) ? Integer.parseInt(dateStrs[2]) : Integer.parseInt(dateStrs[2], 16),
                        Integer.parseInt(timeStrs[0]), Integer.parseInt(timeStrs[1]), Integer.parseInt(timeStrs[2]), 0));
                emergencyProfile.setDuration(limitDataDto.getEmergencyDuration());
                break;
            case 9: // emergency profile group id list
                int[] groupIds = new int[]{limitDataDto.getTemplateId().intValue()};
                gxdlmsLimiter.setEmergencyProfileGroupIDs(groupIds);
                break;
            case 10: // emergency profile active
                gxdlmsLimiter.setEmergencyProfileActive(true);
                break;
            case 11: // actions
                GXDLMSActionItem overItem = new GXDLMSActionItem();
                overItem.setLogicalName("0.0.10.0.106.255");
                overItem.setScriptSelector(Integer.parseInt(limitDataDto.getActionUp()));
                gxdlmsLimiter.setActionOverThreshold(overItem);

                GXDLMSActionItem underItem = new GXDLMSActionItem();
                underItem.setLogicalName("0.0.10.0.106.255");
                underItem.setScriptSelector(Integer.parseInt(limitDataDto.getActionDown()));
                gxdlmsLimiter.setActionUnderThreshold(underItem);
                break;

        }
        try {
            byte[][] b = client.write(gxdlmsLimiter, dlmsSubDataItemDTO.getAttributeId());
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
        }
        return null;
    }

    @Override
    public byte[] setScheduleAction(DataItemDTO dataItemDTO, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys, List<GXDate> dateList, List<GXTime> timeList) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);

        GXDLMSActionSchedule gxdlmsActionSchedule = new GXDLMSActionSchedule();

        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        gxdlmsActionSchedule.setLogicalName(dlmsSubDataItemDTO.getObis());
        java.util.ArrayList<GXDateTime> items = new java.util.ArrayList<GXDateTime>();
        for (int i = 0; i < dateList.size(); i++) {
            // 这里timeList 和dateList个数相等
            GXDateTime time = timeList.get(i);
            time.setSkip(DateTimeSkips.forValue(DateTimeSkips.toInteger(time.getSkip())
                    & ~(DateTimeSkips.YEAR.getValue() | DateTimeSkips.MONTH.getValue()
                    | DateTimeSkips.DAY.getValue() | DateTimeSkips.DAY_OF_WEEK.getValue())));
            GXDateTime date = dateList.get(i);
            date.setSkip(DateTimeSkips.forValue(DateTimeSkips.toInteger(date.getSkip())
                    & ~(DateTimeSkips.HOUR.getValue() | DateTimeSkips.MINUTE.getValue()
                    | DateTimeSkips.SECOND.getValue() | DateTimeSkips.MILLISECOND.getValue())));
            GXDateTime tmp = new GXDateTime(date);
            tmp.getMeterCalendar().add(Calendar.HOUR_OF_DAY, time.getMeterCalendar().get(Calendar.HOUR_OF_DAY));
            tmp.getMeterCalendar().add(Calendar.MINUTE, time.getMeterCalendar().get(Calendar.MINUTE));
            tmp.getMeterCalendar().add(Calendar.SECOND, time.getMeterCalendar().get(Calendar.SECOND));
            tmp.getSkip().addAll(date.getSkip());
            tmp.getSkip().addAll(time.getSkip());
            items.add(tmp);
        }
        gxdlmsActionSchedule.setExecutionTime(items.toArray(new GXDateTime[items.size()]));
        try {
            byte[][] b = client.write(gxdlmsActionSchedule, dlmsSubDataItemDTO.getAttributeId());
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDTO, e);
        }
        return null;
    }

    /*
     * @Description 将时间字符串转换成GXDateTime
     * @Date 2021/11/23 16:05
     * @param data 时间数据格式：FFFF-03-28-FF 03:00:00
     * @return gurux.dlms.GXDateTime
     **/
    private GXDateTime formatGXDateTime(String data) {
        String[] dateTimeStr = data.split(" ");
        String[] dateStrs = dateTimeStr[0].split("-");
        String[] timeStrs = dateTimeStr[1].split(":");

        Function<String, Integer> strToInt = value -> NumberUtil.isNumber(value) ? Integer.parseInt(value) : Integer.parseInt(value, 16);

        return new GXDateTime(strToInt.apply(dateStrs[0]), strToInt.apply(dateStrs[1]), strToInt.apply(dateStrs[2]),
                strToInt.apply(timeStrs[0]), strToInt.apply(timeStrs[1]), strToInt.apply(timeStrs[2]), 0);
    }

    @Override
    public byte[] setClockObjectPacket(DataItemDTO dataItemDTO, Meter meter, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceSAPandKeys, TemplateClockEntity templateClockEntity) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((Objects.isNull(deviceSAPandKeys) || Objects.isNull(deviceSAPandKeys.getWPort())) ? 1 : deviceSAPandKeys.getWPort().intValue());
        client.setServerAddress(1);

        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        GXDLMSClock gxdlmsClock = new GXDLMSClock(dlmsSubDataItemDTO.getObis());
        GXDateTime gxDateTime;

        switch (dlmsSubDataItemDTO.getAttributeId()) {
            case 3:
                gxdlmsClock.setTimeZone(templateClockEntity.getTimeZone().intValue());
                break;
            case 5:
                gxDateTime = formatGXDateTime(templateClockEntity.getDaylightSavingsBegin());
                gxdlmsClock.setBegin(gxDateTime);
                break;
            case 6:
                gxDateTime = formatGXDateTime(templateClockEntity.getDaylightSavingsEnd());
                gxdlmsClock.setEnd(gxDateTime);
                break;
            case 7:
                gxdlmsClock.setDeviation(templateClockEntity.getDaylightSavingsDeviation().intValue());
                break;
            case 8:
                gxdlmsClock.setEnabled(templateClockEntity.getDaylightSavingsEnabled().intValue() != 1 ? false : true);
                break;
            default:
                throw new UDISTaskExecutorException("Not implemented yet");
        }

        try {
            byte[][] bytes = client.write(gxdlmsClock, dlmsSubDataItemDTO.getAttributeId());
            return bytes[0];
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL, e);
        }

        return null;
    }

    @Override
    public byte[] actionTokenDataPacket(List<DataItemDTO> dataItemCosemList, Meter meter, Object value, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys) throws UDISTaskExecutorException {
        if (value == null) {
            return null;
        }

        DLMSSubDataItemDTO dataItemDto = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
//        Object name = dlmsConfigDMO.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));

        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);

        try {
            GXByteBuffer byteBuffer = new GXByteBuffer();
            GXByteBufferUtils.setActionTokenData(byteBuffer, Convert.toStr(value)); //length 2

            byte[] data = new byte[byteBuffer.size()];
            System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());

            byte[][] b = client.method(dataItemDto.getObis(), ObjectType.forValue(dataItemDto.getClassId()), dataItemDto.getMethodId(), data, DataType.STRUCTURE);
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
        }
        return null;
    }

    /**
     * @param dataItemDTO
     * @param keyTransferDTO
     * @param dlmsConfigDMO
     * @param deviceKeys     key_id: enum:
     *                       (0) global unicast encryption key,
     *                       (2) authentication key,
     *                       (1) global broadcast encryption key,
     *                       (3) master key (KEK)
     * @return
     * @throws UDISTaskExecutorException
     */
    @Override
    public byte[] keyTransferDataPacket(DataItemDTO dataItemDTO, KeyTransferDTO keyTransferDTO, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys) throws UDISTaskExecutorException {

        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress((deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue()));
        client.setServerAddress(1);

        try {
            GXByteBuffer byteBuffer = new GXByteBuffer();
            GXByteBufferUtils.setArrayByte(byteBuffer, 1); // default set one array

            GXByteBufferUtils.setStructureByte(byteBuffer, 2);
            GXByteBufferUtils.setEnumByte(byteBuffer, Integer.valueOf(keyTransferDTO.getKeyType()));
            GXByteBufferUtils.setOctStringHexByte(byteBuffer, keyTransferDTO.getKeyValue());

            byte[] data = new byte[byteBuffer.size()];
            System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());

            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
            byte[][] b = client.method(dlmsSubDataItemDTO.getObis(), ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getMethodId(), data, DataType.ARRAY);
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDTO, e);
        }
        return null;
    }

    @Override
    public byte[] buildReadProfilePacket(List<DataItemDTO> dataItemCosemList, Meter meter, Date startDate, Date endDate, DLMSConfigDMO dlmsConfigDMO) {

        DLMSSubDataItemDTO dataItemDto = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        GXDLMSClient client = new GXDLMSClient();
        //is shortName or not
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
//        Object name = meter.getIsShortName() ? Integer.parseInt(dataItemDto.getObis(), 16) : dataItemDto.getObis();

        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));

        // Read http://www.gurux.org/dlmsAddress
        // to find out how Client and Server addresses are counted.
        // Some manufacturers might use own Server and Client addresses.
        client.setClientAddress(1);
        client.setServerAddress(1);
        GXDLMSProfileGeneric profileGeneric = new GXDLMSProfileGeneric();
        if (dlmsConfigDMO.getIsShortName()) {
            profileGeneric.setShortName(Integer.parseInt(dataItemDto.getObis(), 16));
        } else {
            profileGeneric.setLogicalName(dataItemDto.getObis());
        }
        //设置以时间排序
        profileGeneric.addCaptureObject(new GXDLMSObject(), 1, 1);
        GXDLMSObject sort = new GXDLMSObject();
        sort.setLogicalName("0.0.1.0.0.255");
        sort.setObjectType(ObjectType.CLOCK);
        profileGeneric.setSortObject(sort);
        GXDateTime gxStartDate = new GXDateTime(startDate);
        gxStartDate.getStatus().add(ClockStatus.SKIPPED);
        gxStartDate.getSkip().add(DateTimeSkips.DEVITATION);
        GXDateTime gxEndDate = new GXDateTime(endDate);
        gxEndDate.getStatus().add(ClockStatus.SKIPPED);
        gxEndDate.getSkip().add(DateTimeSkips.DEVITATION);
        try {
            byte[][] b = client.readRowsByRange(profileGeneric, gxStartDate, gxEndDate);
            return b[0];
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDto, e);
        }

        return new byte[0];
    }

    @Override
    public PacketParseResult parsePacket(List<byte[]> results, Task task, DLMSConfigDMO dlmsConfigDMO) {
        PacketParseResult result = new PacketParseResult();
//        Meter meter = assetManagementRemoteService.getMeterById(task.getMeterId());
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        // Is used HDLC or COSEM transport layers for IPv4 networks (WRAPPER).
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        GXReplyData data = new GXReplyData();
        GXByteBuffer buffer = new GXByteBuffer();
        buffer.set(results.get(0));
        try {
            client.getData(buffer, data);
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error("analyse data wrong", e);
        }
        GXDLMSTranslator t = new GXDLMSTranslator(TranslatorOutputType.SIMPLE_XML);
        String xml = t.dataToXml(data.getData());
        log.info(xml);
        if (StringUtils.isNotEmpty(xml)) {
            result.setResultCosemXml(xml);
            result.setComplete(true);
            result.setIsCorrect(false);
        } else {
            log.error("decode data fail");
        }
        return result;
    }

    /**
     * DLMS gate Way
     *
     * @param terminal
     * @param meters
     * @param dataItemCosemList
     * @return
     */
    @Override
    public byte[][] writeDCUMeterList(ComEntity terminal, List<Meter> meters, List<DataItemDTO> dataItemCosemList, DLMSConfigDMO dlmsConfigDMO) {
        DLMSSubDataItemDTO dataItemDTO = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();
        GXByteBufferUtils.setArrayByte(byteBuffer, meters.size());
        for (Meter meter : meters) {
            if (meter != null && meter.getMeterId() != null) {
                setBufferMeterInfo(byteBuffer, meter);
            }
        }

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        try {
            return client.write(dataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dataItemDTO.getClassId()), dataItemDTO.getAttributeId());
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }

        return null;
    }

    private void setBufferMeterInfo(GXByteBuffer byteBuffer, Meter meter) {

//        DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), 1);
        DeviceSAPandKeys deviceKeys = kmsService.getMeterCommunicationKeyForHls(meter.getMeterId(), 1);
        log.info("add dcu meter info {}, {}, {}", meter.getMeterId(), meter.getMfgSn(), deviceKeys);

        SecurityHls hls = null;
        if (CollectionUtils.isNotEmpty(deviceKeys.getHlsKeys())) {
            hls = deviceKeys.getHlsKeys().get(0);
        }

        //Structure
        GXByteBufferUtils.setStructureByte(byteBuffer, 13);

        // Without Datacollector
        GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, "");
        // MeterNo
        GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, meter.getMfgSn());
        // ProtocolType‐ DLMS/COSEM
        GXByteBufferUtils.setUnsignedByte(byteBuffer, 0);
        // CommType‐ CommTypeRf/PLC
        GXByteBufferUtils.setEnumByte(byteBuffer, 1);
        // Initiate control word
        GXByteBufferUtils.setUnsignedByte(byteBuffer, 43);
        // ClientId
        GXByteBufferUtils.setUnsignedByte(byteBuffer, 1);
        // SecurityControl, meter security mechanism is HLS with suite 0, authentication and encryption are applied
        GXByteBufferUtils.setUnsignedByte(byteBuffer, 16);
        // ContextId, COSEM context using LN referencing, message encrypted
        GXByteBufferUtils.setUnsignedByte(byteBuffer, 1);
        // SecurityKey  EK=   AK=
        byteBuffer.setUInt8(DataType.OCTET_STRING.getValue());
        if (hls != null) {
            DeviceTypeGroup dtg = redisUtils.getDeviceTypeGroup(meter.getModelId(), null, assetManagementRemoteService);
            // 威胜电表白名单设置：判断是否为威胜电表以及数据库配置开关是否开启
            if (dtg.getManufacturerId() == DeviceMfg.MF_Wasion) {
                String value = assetManagementRemoteService.getPropertyValue("ENCRYPT_HLS_KEYS");
                if (Constant.TRUE.equalsIgnoreCase(value) && StrUtil.isNotEmpty(hls.getKek())) {
                    StringBuilder sk = new StringBuilder()
                            .append(AesUtils.wrap(hls.getKek(), hls.getGuek()))
                            .append(AesUtils.wrap(hls.getKek(), hls.getGak()));
                    byteBuffer.setUInt8(sk.toString().length() / 2);
                    byteBuffer.setHexString(sk.toString());
                } else {
                    byteBuffer.setUInt8(32);
                    byteBuffer.setHexString(hls.getGuek() + hls.getGak());
                }
            } else {
                byteBuffer.setUInt8(32);
                byteBuffer.setHexString(hls.getGuek() + hls.getGak());
            }
        } else {
            byteBuffer.setUInt8(0);
        }
        // MechanismId
        if (null != meter.getSecurityLevel() && meter.getSecurityLevel() == SecurityLevel.HLS.getCode()) {
            //HLS Mechanism Id 设置为5
            GXByteBufferUtils.setUnsignedByte(byteBuffer, 5);
        } else {
            GXByteBufferUtils.setUnsignedByte(byteBuffer, 1);
        }
        // MechanismKey
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, deviceKeys.getLlsKey());
        // DedKeyEnable, disable
        GXByteBufferUtils.setBooleanByte(byteBuffer, false);
        // PSK
        byteBuffer.setUInt8(DataType.OCTET_STRING.getValue());
        byteBuffer.setUInt8(0);
    }

    @Override
    public byte[][] deleteDCUMeterList(ComEntity comEntity, List<String> serialNums, List<DataItemDTO> dataItemCosemList, ComConfigDMO dlmsConfigDMO) {
        DLMSSubDataItemDTO dataItemDTO = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();
        GXByteBufferUtils.setArrayByte(byteBuffer, serialNums.size());
        for (String serialNum : serialNums) {
            GXByteBufferUtils.setStructureByte(byteBuffer, 2);
            // device serial number
            GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, serialNum);
            // device type
            GXByteBufferUtils.setUnsignedByte(byteBuffer, 0);
        }

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        try {
            return client.write(dataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dataItemDTO.getClassId()), dataItemDTO.getAttributeId());
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }

        return null;
    }

    @Override
    public byte[] buildDCUScheduleRead(ComEntity comEntity, Meter meter, DataItemDTO dataItemDTO, DataItemDTO profileDataItemDTO, Date startDate, Date endDate, DLMSConfigDMO dlmsConfigDMO, DeviceSAPandKeys deviceKeys) {

//        DeviceSAPandKeys deviceKeys = null; //for Test
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue());
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());


        try {
            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
            byte[][] b = client.read(dlmsSubDataItemDTO.getObis(), ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
            GXByteBuffer attributeDescriptor = new GXByteBuffer();
            // Add AccessSelector flag.
            attributeDescriptor.setUInt8(0x01);
            // Add AccessSelector value.
            attributeDescriptor.setUInt8(02);
            //Array
            GXByteBufferUtils.setArrayByte(attributeDescriptor, 1); // count 1
            //Structure
            GXByteBufferUtils.setStructureByte(attributeDescriptor, 5); // count 5
            //meter no
            GXByteBufferUtils.setVisibleStringAsciiByte(attributeDescriptor, meter.getMfgSn());
            //profileObis
            GXByteBufferUtils.setOctStringObisByte(attributeDescriptor, ((DLMSSubDataItemDTO) profileDataItemDTO).getObis());
            //start end Time
            GXDateTime startDateGx = GXCommon.getDateTime(startDate);
            GXDateTime endDateGx = GXCommon.getDateTime(endDate);
            GXByteBufferUtils.setDateTime(attributeDescriptor, startDateGx);
            GXByteBufferUtils.setDateTime(attributeDescriptor, endDateGx);

            //Array
            GXByteBufferUtils.setArrayByte(attributeDescriptor, 0);

            byte[] data = new byte[attributeDescriptor.size()];
            System.arraycopy(attributeDescriptor.getData(), 0, data, 0, attributeDescriptor.size());

            GXDLMSTranslator translator = new GXDLMSTranslator(TranslatorOutputType.SIMPLE_XML);
            byte[] pdu = translator.getPdu(b[0]);
            int wrapIndex = Bytes.indexOf(b[0], pdu);
            byte[] packet = Bytes.concat(Arrays.copyOfRange(b[0], 0, b[0].length - 1), data);
//            log.info(ByteUtils.byteToHexString(packet));
            Integer pduLength = packet.length - wrapIndex;
            byte[] pduLengthByte = ByteNumberUtils.shortToByte2(pduLength.shortValue());
//            log.info("length pdu {}",  ByteUtils.byteToHexString(pduLengthByte));
            //change length of pdu
            System.arraycopy(pduLengthByte, 0, packet, wrapIndex - 2, 2);
            return packet;
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL, e);
            return null;
        }


    }


    @Override
    public byte[] imageTransferInitAction(DataItemDTO dataItem, String interfaceType, Boolean isShortName, Integer wPort, String identifier, Long imageSize) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!isShortName);
        client.setInterfaceType(InterfaceType.valueOf(interfaceType));
        client.setClientAddress(wPort);
        client.setServerAddress(1);
        GXDLMSImageTransfer transfer = new GXDLMSImageTransfer();
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
        transfer.setLogicalName(dlmsSubDataItemDTO.getObis());
        transfer.setObjectType(ObjectType.forValue(dlmsSubDataItemDTO.getClassId()));
        try {
            byte[][] bytes = transfer.imageTransferInitiate(client, identifier, imageSize);
            return bytes[0];
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL);
        }
        return null;
    }

    @Override
    public byte[] imageBlockTransferAction(DataItemDTO dataItem, String interfaceType, DLMSConfigDMO dlmsConfigDMO, Boolean isShortName, Integer wPort, byte[] fileImageBlock, int blockNumber) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!isShortName);
        client.setInterfaceType(InterfaceType.valueOf(interfaceType));
        client.setClientAddress(wPort);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());
        GXByteBuffer byteBuffer = new GXByteBuffer();
        GXByteBufferUtils.setStructureByte(byteBuffer, 2); //length 2
        byteBuffer.setUInt8(DataType.UINT32.getValue());//double-long-unsigned
        byteBuffer.set(ByteNumberUtils.intToByte4(blockNumber));
        byteBuffer.setUInt8(DataType.OCTET_STRING.getValue());
        GXCommon.setObjectCount(fileImageBlock.length, byteBuffer);
        byteBuffer.set(fileImageBlock);
        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
        try {
            byte[][] bytes = client.method(dlmsSubDataItemDTO.getObis(), ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getMethodId(), data, DataType.STRUCTURE);
            return bytes[0];
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL);
        }
        return null;
    }


    @Override
    public byte[] imageTransferVerifyAction(DataItemDTO dataItem, String interfaceType, Boolean isShortName, Integer wPort) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!isShortName);
        client.setInterfaceType(InterfaceType.valueOf(interfaceType));
        client.setClientAddress(wPort);
        client.setServerAddress(1);
        GXDLMSImageTransfer transfer = new GXDLMSImageTransfer();
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
        transfer.setLogicalName(dlmsSubDataItemDTO.getObis());
        transfer.setObjectType(ObjectType.forValue(dlmsSubDataItemDTO.getClassId()));
        try {
            byte[][] bytes = transfer.imageVerify(client);
            return bytes[0];
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL);
        }
        return null;
    }

    @Override
    public byte[] imageTransferActivation(DataItemDTO dataItem, String interfaceType, Boolean isShortName, Integer wPort) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!isShortName);
        client.setInterfaceType(InterfaceType.valueOf(interfaceType));
        client.setClientAddress(wPort);
        client.setServerAddress(1);
        GXDLMSImageTransfer transfer = new GXDLMSImageTransfer();
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
        transfer.setLogicalName(dlmsSubDataItemDTO.getObis());
        transfer.setObjectType(ObjectType.forValue(dlmsSubDataItemDTO.getClassId()));
        try {
            byte[][] bytes = transfer.imageActivate(client);
            return bytes[0];
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL);
        }
        return null;
    }

    @Override
    public byte[] setClockTimePacket(DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO, Long modelId, DeviceSAPandKeys deviceKeys, Date date) {
        if (dataItemDTO instanceof AnsiSubDataItemDTO) {
            byte[] data = AnsiUtil.formatDatetimePacket(modelId, "+00:00", date);
            Acse acse = new Acse(deviceKeys.getLlsKey(), data, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));
            return acse.getPacket();
        } else {
            GXDLMSClient client = new GXDLMSClient();
            client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
            client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
            client.setClientAddress(deviceKeys == null || deviceKeys.getWPort() == null ? 1 : deviceKeys.getWPort().intValue());
            client.setServerAddress(1);
            setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());
            GXDateTime gxDateTime = new GXDateTime(date);
            if (Arrays.stream(clockStatusOkModelId).map(Convert::toLong).anyMatch(modelId::equals)) {
                gxDateTime.getStatus().add(ClockStatus.OK);
            } else {
                gxDateTime.getStatus().add(ClockStatus.SKIPPED);
            }
            gxDateTime.getSkip().add(DateTimeSkips.DEVITATION);
            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
            try {
                byte[][] bytes = client.write(dlmsSubDataItemDTO.getObis(), gxDateTime, DataType.OCTET_STRING, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
                return bytes[0];
            } catch (Exception e) {
                log.error(BUILD_PACKET_FAIL, e);
            }
            return null;
        }
    }

    @Override
    public byte[] disconnectControlAction(DataItemDTO dataItem, String interfaceType, Boolean isShortName, DeviceSAPandKeys deviceKeys) {
        if (dataItem instanceof AnsiSubDataItemDTO) {
            AnsiSubDataItemDTO ansiSubDataItemDTO = (AnsiSubDataItemDTO) dataItem;
            byte[] data = AnsiUtil.formatConnectDisconnectPacket(ansiSubDataItemDTO.getTableId(), ansiSubDataItemDTO.getProcedureId());
            Acse acse = new Acse(deviceKeys.getLlsKey(), data, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));
            return acse.getPacket();
        } else {
            DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
            GXDLMSClient client = new GXDLMSClient();
            client.setUseLogicalNameReferencing(!isShortName);
            client.setInterfaceType(InterfaceType.valueOf(interfaceType));
            client.setClientAddress(deviceKeys.getWPort().intValue());
            client.setServerAddress(1);

            GXByteBuffer byteBuffer = new GXByteBuffer();
            byteBuffer.setUInt8(DataType.INT8.getValue());
            byteBuffer.setUInt8(0);

            byte[] data = new byte[byteBuffer.size()];
            System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
            try {
                byte[][] bytes = client.method(dlmsSubDataItemDTO.getObis(), ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getMethodId(), data, DataType.STRUCTURE);
                return bytes[0];
            } catch (Exception e) {
                log.error(BUILD_PACKET_FAIL);
            }
            return null;
        }
    }

    @Override
    public byte[] upgradeSettings(Long modelId, DataItemDTO dataItem, AtomicTask atomicTask, Map<String, Object> params, String interfaceType, Boolean isShortName, Integer wPort) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!isShortName);
        client.setInterfaceType(InterfaceType.valueOf(interfaceType));
        client.setClientAddress(wPort);
        client.setServerAddress(1);

        GXByteBuffer byteBuffer = new GXByteBuffer();
        int constructCount = 5;
        Integer transferType = MapUtil.getInt(params, "transferType");
        switch (OperationName.forId(atomicTask.getOperationId())) {
            case MModUpgradeSettings:
            case DCUUpgradeSettings:
                constructCount = 5;
                break;
            case SModUpgradeSettings:
                constructCount = 6;
                break;
            case MeterUpgradeSettings:
                if (transferType != null) {
                    if (TemplateFwUpgrade.TransferType.Broadcast.getCode() == transferType) {
                        // 威士顿不需要传空array
                        if (modelId.equals(Convert.toLong(DeviceModel.DF6203))) {
                            constructCount = 5;
                        } else {
                            constructCount = 6;
                        }
                    } else {
                        constructCount = 6;
                    }
                } else {
                    constructCount = 6;
                }
                break;
            default:
                log.info("no implementation of this type {}", atomicTask.getOperationId());
        }
        GXByteBufferUtils.setStructureByte(byteBuffer, constructCount);
        if (atomicTask.getOperationId() == OperationName.MeterUpgradeSettings.getId().longValue()
                || atomicTask.getOperationId() == OperationName.SModUpgradeSettings.getId().longValue()) {
            if (constructCount == 6) {
                if (transferType != null && TemplateFwUpgrade.TransferType.Broadcast.getCode() == transferType) {
                    GXByteBufferUtils.setArrayByte(byteBuffer, 0);
                } else {
                    String meterIdsStr = MapUtil.getStr(params, "meterIds");
                    String[] meterIds = meterIdsStr.split(",");
                    GXByteBufferUtils.setArrayByte(byteBuffer, meterIds.length);
                    for (String meterId : meterIds) {
                        Meter meter = assetManagementRemoteService.getMeterById(Convert.toLong(meterId));
                        if (meter != null) {
                            GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, meter.getMfgSn());
                        } else {
                            GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, "");
                        }
                    }
                }
            }
        }
        // FileName
        String fileName = MapUtil.getStr(params, "fileName");
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, fileName);
        // FileType ：
        // 01H‐DCU file，
        // FDH‐meter file(Active firmware Identifier)
        // F7H‐meter file(Active firmware Identifier 1)
        byteBuffer.setUInt8(DataType.UINT8.getValue());
        switch (OperationName.forId(atomicTask.getOperationId())) {
            case MeterUpgradeSettings:
                byteBuffer.setUInt8(0xFD);
                break;
            case DCUUpgradeSettings:
                byteBuffer.setUInt8(0x01);
                break;
            case SModUpgradeSettings:
                byteBuffer.setUInt8(0xF7);
                break;
            case MModUpgradeSettings:
                //WISUN gateway的7300模块升级的fileType是0x03
                Object fwFileTypeIdObj = MapUtil.getStr(params, "fwFileTypeId");
                if (null != fwFileTypeIdObj) {
                    Long fwFileTypeId = Convert.toLong(fwFileTypeIdObj);
                    if (fwFileTypeId.equals(11L)) {
                        byteBuffer.setUInt8(0x03);
                    } else {
                        byteBuffer.setUInt8(0x02);
                    }
                } else {
                    byteBuffer.setUInt8(0x02);
                }
                break;
            default:
                log.info("no implementation of this type {}", atomicTask.getOperationId());
        }
        // ImageIdentifier
        String imageIdentifier = MapUtil.getStr(params, "imageIdentifier");
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, imageIdentifier);
        // ImageSize
        GXByteBufferUtils.setDoubleLongUnsignedByte(byteBuffer, MapUtil.getLong(params, "imageSize"));
        // Active_time
        GXByteBufferUtils.setDateTime(byteBuffer, GXDateTime.fromUnixTime(MapUtil.getLong(params, "activeTime")));

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.STRUCTURE, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }

        return null;
    }

    @Override
    public byte[][] setDCUDataCollTask(List<TemplateDcuAutoCollTask> dcuCollTasks, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setArrayByte(byteBuffer, dcuCollTasks.size());

        for (TemplateDcuAutoCollTask dcuCollTask : dcuCollTasks) {

            GXByteBufferUtils.setStructureByte(byteBuffer, 8);

            GXByteBufferUtils.setOctStrDateTime(byteBuffer, dcuCollTask.getTvUploadBase());

            GXByteBufferUtils.setEnumByte(byteBuffer, dcuCollTask.getUploadCircleUnit());

            GXByteBufferUtils.setLongUnsignedByte(byteBuffer, Math.toIntExact(dcuCollTask.getUploadCircle()));

            GXByteBufferUtils.setUnsignedByte(byteBuffer, Math.toIntExact(dcuCollTask.getTaskNo()));

            GXByteBufferUtils.setEnumByte(byteBuffer, Math.toIntExact(dcuCollTask.getTaskType()));

            GXByteBufferUtils.setArrayByte(byteBuffer, dcuCollTask.getObisList().size());
            for (String taskObis : dcuCollTask.getObisList()) {
                GXByteBufferUtils.setOctStringObisByte(byteBuffer, taskObis);
            }

            GXByteBufferUtils.setOctStrDateTime(byteBuffer, dcuCollTask.getTvDataGather());

            GXByteBufferUtils.setLongUnsignedByte(byteBuffer, Math.toIntExact(dcuCollTask.getDcuCollectionTimeliness()));
        }

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }

        return null;
    }

    @Override
    public byte[] setDCUMeterTask(boolean isClearMeterTask, List<String> meterNos, List<DcuMeterTaskDto> dcuMeterTasks, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        if (isClearMeterTask) {
            // 清除meterTask
            GXByteBufferUtils.setArrayByte(byteBuffer, meterNos.size());
            for (String meterNo : meterNos) {
                GXByteBufferUtils.setStructureByte(byteBuffer, 2);
                if (StrUtil.equalsIgnoreCase("allMeter", meterNo)) {
                    // meterTask统一设置时下发 0A 00 (0A是VisibleString)
                    GXByteBufferUtils.setVisibleStringHexByte(byteBuffer, "");
                } else {
                    GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, meterNo);
                }
                GXByteBufferUtils.setArrayByte(byteBuffer, 0);
            }
        } else {
            GXByteBufferUtils.setArrayByte(byteBuffer, dcuMeterTasks.size());
            for (DcuMeterTaskDto meterTaskDto : dcuMeterTasks) {
                GXByteBufferUtils.setStructureByte(byteBuffer, 2);

                if (StrUtil.equalsIgnoreCase("allMeter", meterTaskDto.getMeterSerialNo())) {
                    // meterTask统一设置时下发 0A 00 (0A是VisibleString)
                    GXByteBufferUtils.setVisibleStringHexByte(byteBuffer, "");
                } else {
                    GXByteBufferUtils.setVisibleStringAsciiByte(byteBuffer, meterTaskDto.getMeterSerialNo());
                }

                GXByteBufferUtils.setArrayByte(byteBuffer, meterTaskDto.getTaskNos().size());
                for (Long taskNo : meterTaskDto.getTaskNos()) {
                    GXByteBufferUtils.setUnsignedByte(byteBuffer, Math.toIntExact(taskNo));
                }
            }
        }

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }

        return null;
    }

    @Override
    public byte[] setDCUSimpleData(Object value, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) throws UDISTaskExecutorException {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;

        try {
            DlmsDataType dlmsDataType = DlmsDataType.forName(dlmsSubDataItemDTO.getObjType());
            if (null == dlmsDataType) {
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.BUILD_PACKET_ERROR_ITEM_INVALID.toString() + dataItemDTO.toString());
            }
            boolean isCustomClassId = false;
            if (null == ObjectType.forValue(dlmsSubDataItemDTO.getClassId())) {
                isCustomClassId = true;
            }
            if (isCustomClassId) {
                // 自定义不支持的classId 先用1类组报文后 再替换掉classId
                byte[][] b = client.write(dlmsSubDataItemDTO.getObis(), value, DataType.forValue(dlmsDataType.getValue()), ObjectType.forValue(1), dlmsSubDataItemDTO.getAttributeId());
                b[0][11] = (byte) ((dlmsSubDataItemDTO.getClassId() >> 8) & 0xFF);
                b[0][12] = (byte) (dlmsSubDataItemDTO.getClassId() & 0xFF);
                return b[0];
            } else {
                byte[][] b = client.write(dlmsSubDataItemDTO.getObis(), value, DataType.forValue(dlmsDataType.getValue()), ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
                return b[0];
            }

        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            log.error(COMPOSE_BYTE_ERROR, dataItemDTO, e);
        }
        return new byte[0];
    }

    @Override
    public byte[] setDCUGPRSParamData(TemplateParamsDcuGprs templateParamsDcuGprs, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setStructureByte(byteBuffer, 7);
        GXByteBufferUtils.setOctStringIpAddrByte(byteBuffer, templateParamsDcuGprs.getMainServerIp());
        GXByteBufferUtils.setLongUnsignedByte(byteBuffer, templateParamsDcuGprs.getMainServerPort().intValue());
        GXByteBufferUtils.setOctStringIpAddrByte(byteBuffer, templateParamsDcuGprs.getBackupServerIp());
        GXByteBufferUtils.setLongUnsignedByte(byteBuffer, templateParamsDcuGprs.getBackupServerPort().intValue());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, templateParamsDcuGprs.getApn());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, templateParamsDcuGprs.getUserName());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, templateParamsDcuGprs.getUserPsw());

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.STRUCTURE, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }
        return null;
    }

    @Override
    public byte[] setDCUEthernetParamData(TemplateParamsDcuEthernet templateParamsDcuEthernet, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setStructureByte(byteBuffer, 3);
        GXByteBufferUtils.setOctStringIpAddrByte(byteBuffer, templateParamsDcuEthernet.getLocalIp());
        GXByteBufferUtils.setOctStringIpAddrByte(byteBuffer, templateParamsDcuEthernet.getSubnetMask());
        GXByteBufferUtils.setOctStringIpAddrByte(byteBuffer, templateParamsDcuEthernet.getGateway());

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.STRUCTURE, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }
        return null;
    }

    @Override
    public byte[] setDCUBasicParamData(TemplateParamsDcuBasic templateParamsDcuBasic, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setStructureByte(byteBuffer, 5);
        GXByteBufferUtils.setUnsignedByte(byteBuffer, templateParamsDcuBasic.getResendTimes());
        GXByteBufferUtils.setLongUnsignedByte(byteBuffer, templateParamsDcuBasic.getRedialPeriod());
        GXByteBufferUtils.setUnsignedByte(byteBuffer, templateParamsDcuBasic.getRedialTimes());
        GXByteBufferUtils.setUnsignedByte(byteBuffer, templateParamsDcuBasic.getOnlineMsg());
        GXByteBufferUtils.setUnsignedByte(byteBuffer, templateParamsDcuBasic.getNetStandard());

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.STRUCTURE, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }
        return null;
    }

    @Override
    public byte[] setDCUFtpParamData(FtpDataDto ftpDataDto, DataItemDTO dataItemDTO, DLMSConfigDMO dlmsConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!dlmsConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(dlmsConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, dlmsConfigDMO.getInterfaceType(), dlmsConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setStructureByte(byteBuffer, 6);
        GXByteBufferUtils.setEnumByte(byteBuffer, ftpDataDto.getProtocolType());
        GXByteBufferUtils.setBooleanByte(byteBuffer, ftpDataDto.isUploadEnable());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, ftpDataDto.getUploadUri());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, ftpDataDto.getUploadPw());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, ftpDataDto.getDownLoadUri());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, ftpDataDto.getDownLoadPw());

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.STRUCTURE, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }
        return null;
    }

    @Override
    public byte[] setDcuAutoConnect(TemplateParamsDcuAutoConnect autoConnect, DataItemDTO dataItemDTO, ComConfigDMO comConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!comConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(comConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, comConfigDMO.getInterfaceType(), comConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setArrayByte(byteBuffer, 2);
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, autoConnect.getMainServerIp() + ":" + autoConnect.getMainServerPort());
        GXByteBufferUtils.setOctStringAsciiByte(byteBuffer, autoConnect.getBackupServerIp() + ":" + autoConnect.getBackupServerPort());

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId())[0];
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }
        return null;
    }

    @Override
    public byte[][] setLongArrayToData(DataItemDTO dataItemDTO, MeterConfigDMO comConfigDMO, List<Long> values) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!comConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(comConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, comConfigDMO.getInterfaceType(), comConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();

        GXByteBufferUtils.setArrayByte(byteBuffer, values.size());
        values.stream().forEach(step -> GXByteBufferUtils.setDoubleLongUnsignedByte(byteBuffer, step));
        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemDTO;
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }
        return null;
    }

    @Override
    public byte[][] getProcedurePacket(DataItemDTO dataItemDTO, Meter meter) {
        AnsiSubDataItemDTO ansiSubDataItemDTO = (AnsiSubDataItemDTO) dataItemDTO;
        byte[] data = AnsiUtil.formatProcedure(ansiSubDataItemDTO);
        DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemDTO.getRoleId());
        Acse acse = new Acse(deviceKeys.getLlsKey(), data, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));
        return new byte[][]{acse.getPacket()};
    }

    @Override
    public byte[] profileCaptureAction(DataItemDTO dataItem, String interfaceType, Object data, Boolean isShortName, DeviceSAPandKeys deviceKeys) {
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItem;
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!isShortName);
        client.setInterfaceType(InterfaceType.valueOf(interfaceType));
        client.setClientAddress(deviceKeys.getWPort().intValue());
        client.setServerAddress(1);
        try {
            byte[][] bytes = client.method(dlmsSubDataItemDTO.getObis(), ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getMethodId(), data, DataType.INT8);
            return bytes[0];
        } catch (Exception e) {
            log.error(BUILD_PACKET_FAIL);
        }
        return null;
    }

    @Override
    public byte[][] writeDisplayCodeList(List<Integer> codeList, List<DataItemDTO> dataItemCosemList, DLMSConfigDMO comConfigDMO) {
        GXDLMSClient client = new GXDLMSClient();
        client.setUseLogicalNameReferencing(!comConfigDMO.getIsShortName());
        client.setInterfaceType(InterfaceType.valueOf(comConfigDMO.getInterfaceType()));
        client.setClientAddress(1);
        client.setServerAddress(1);
        setMaxPduSize(client, comConfigDMO.getInterfaceType(), comConfigDMO.getMaxPduSize());

        GXByteBuffer byteBuffer = new GXByteBuffer();
        GXByteBufferUtils.setArrayByte(byteBuffer, codeList.size());
        for (Integer code : codeList) {
            byteBuffer.setUInt8(DlmsDataType.OctetString.getValue());
            byteBuffer.setUInt8(8);
            byteBuffer.set(String.format("%03d", code).getBytes(Charset.forName("utf-8")));
            byteBuffer.set(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00});
        }

        byte[] data = new byte[byteBuffer.size()];
        System.arraycopy(byteBuffer.getData(), 0, data, 0, byteBuffer.size());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        try {
            return client.write(dlmsSubDataItemDTO.getObis(), data, DataType.ARRAY, ObjectType.forValue(dlmsSubDataItemDTO.getClassId()), dlmsSubDataItemDTO.getAttributeId());
        } catch (Exception e) {
            log.error(ENCODE_PACKET_FAIL, e);
        }

        return null;
    }

    @Override
    public byte[] ansiWriteFullTable(int tableId, byte[] data, Long meterId) {
        byte[] packets = AnsiUtil.formatPacketWriteFullTable(tableId, data, data.length);
        DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meterId, 2);
        Acse acse = new Acse(deviceKeys.getLlsKey(), packets, Convert.toInt(assetService.getSystemProperty("SECURITY_MODE")));

        return acse.getPacket();
    }
}
